home *** CD-ROM | disk | FTP | other *** search
- /*
- * A more or less BSD compatable socket library for MacTCP
- *
- * Summer 1989, Tom Milligan, University of Toronto Computing Services
- */
-
-
- #include <Events.h>
- #include <memory.h>
- #include <types.h>
- #include <OSUtils.h> /* for SysBeep */
- #include <Events.h> /* for TickCount */
-
- #include <stdio.h>
-
- #include <sys/types.h>
- #include <sys/time.h>
- #include <sys/errno.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <sys/uio.h>
-
- #include "tcpglue.h"
- #include "socket.internal.h"
-
-
- /*
- * asynchronous notification routine
- */
- static int notified = 0;
- static int lastNotifyCount = 0;
-
- static StreamPtr notifyTcpStream;
- static unsigned short notifyEventCode;
- static Ptr notifyUserDataPtr;
- static unsigned short notifyTerminReason;
- static struct ICMPReport *notifyIcmpMsg;
-
- pascal void sock_tcp_notify(tcpStream,eventCode,userDataPtr,terminReason,icmpMsg)
- StreamPtr tcpStream;
- unsigned short eventCode;
- Ptr userDataPtr;
- unsigned short terminReason;
- struct ICMPReport *icmpMsg;
- {
- notified++;
-
- notifyTcpStream = tcpStream;
- notifyEventCode = eventCode;
- notifyUserDataPtr = userDataPtr;
- notifyTerminReason = terminReason;
- notifyIcmpMsg = icmpMsg;
- }
-
- static char *eventNames[] =
- {
- "event 0",
- "closing",
- "ULP timeout",
- "terminate",
- "data arrival",
- "urgent data",
- "ICMP message"
- };
- static char *terminateReasons[] =
- {
- "reason 0",
- "reason 1",
- "remote abort",
- "network failure",
- "security/precedence mismatch",
- "ULP timeout",
- "ULP abort",
- "ULP close",
- "service failure"
- };
- static char *icmpMessages[] =
- {
- "net unreachable",
- "host unreachable",
- "protocol unreachable",
- "port unreachable",
- "fragmentation required",
- "source route failed",
- "time exceeded",
- "parameter problem",
- "missing required option"
- };
- tcpCheckNotify()
- {
- if (notified == lastNotifyCount)
- return;
-
- lastNotifyCount = notified;
- dprintf("notify count is now %d\n",lastNotifyCount);
- dprintf("stream %08x\n",notifyTcpStream);
- dprintf("event %d '%s'\n",notifyEventCode,eventNames[notifyEventCode]);
- if (notifyEventCode == TCPTerminate)
- dprintf("reason %d '%s'\n",notifyTerminReason,terminateReasons[notifyTerminReason]);
- if (notifyEventCode == TCPDataArrival)
- dprintf("%d bytes\n",notifyTerminReason/*!?*/);
- dprintf("icmp msg %08x\n",notifyIcmpMsg);
- if (notifyEventCode == TCPICMPReceived)
- {
- dprintf("stream %08x\n",notifyIcmpMsg->streamPtr);
- dprintf("local %08x/%d\n",notifyIcmpMsg->localHost,notifyIcmpMsg->localPort);
- dprintf("remote %08x/%d\n",notifyIcmpMsg->remoteHost,notifyIcmpMsg->remotePort);
- dprintf("%s\n",icmpMessages[notifyIcmpMsg->reportType]);
- dprintf("optionalAddlInfo %04x\n",notifyIcmpMsg->optionalAddlInfo);
- dprintf("optionalAddlInfoPtr %08x\n",notifyIcmpMsg->optionalAddlInfoPtr);
- }
- dprintf("userdata %s\n",notifyUserDataPtr);
- }
-
- /*
- * sock_tcp_new_stream
- *
- * Create a new tcp stream.
- */
- sock_tcp_new_stream(sp)
- SocketPtr sp;
- {
- OSErr io;
- int i;
-
- #if SOCK_TCP_DEBUG >= 2
- sock_print("sock_tcp_new_stream", sp);
- #endif
-
- io = xTCPCreate(STREAM_BUFFER_SIZE, sock_tcp_notify, &sp->pb.tcp);
- switch(io)
- {
- case noErr: break;
- case streamAlreadyOpen: return(sock_err(io));
- case invalidLength: return(sock_err(ENOBUFS));
- case invalidBufPtr: return(sock_err(ENOBUFS));
- case insufficientResources: return(sock_err(EMFILE));
- default: /* error from PBOpen */ return(sock_err(ENETDOWN));
- }
- sp->sstate = SOCK_STATE_UNCONNECTED;
- sp->peer.sin_family = AF_INET;
- sp->peer.sin_addr.s_addr = 0;
- sp->peer.sin_port = 0;
- bzero(&sp->peer.sin_zero[0], 8);
- sp->dataavail = 0;
- sp->asyncerr = 0;
-
- sp->pb.tcp.ioResult = noErr;
-
- sp->apb.pb.tcp.tcpStream = sp->pb.tcp.tcpStream;
- sp->apb.pb.tcp.ioResult = noErr;
-
- for (i=0; i<TCP_MAX_WRITES; i++)
- {
- sp->wpb[i].pb.tcp.tcpStream = sp->pb.tcp.tcpStream;
- sp->wpb[i].pb.tcp.ioResult = noErr;
- }
- sp->nextwpb = 0;
-
- return(0);
- }
-
-
- /*
- * sock_tcp_connect - initiate a connection on a TCP socket
- *
- */
- sock_tcp_connect(sp, addr)
- SocketPtr sp;
- struct sockaddr_in *addr;
- {
- OSErr io;
- void sock_tcp_connect_done();
-
- #if SOCK_TCP_DEBUG >= 2
- sock_print("sock_tcp_connect",sp);
- #endif
-
- /* Make sure this socket can connect. */
- if (sp->sstate == SOCK_STATE_CONNECTING)
- return(sock_err(EALREADY));
- if (sp->sstate != SOCK_STATE_UNCONNECTED)
- return(sock_err(EISCONN));
-
- sp->sstate = SOCK_STATE_CONNECTING;
- io = xTCPActiveOpen(&sp->apb.pb.tcp, sp->sa.sin_port,
- addr->sin_addr.s_addr, addr->sin_port,
- sock_tcp_connect_done);
- if (io != noErr)
- {
- sp->sstate = SOCK_STATE_UNCONNECTED;
- return(sock_err(io));
- }
-
- if (sp->nonblocking)
- return(sock_err(EINPROGRESS));
-
- /* sync connect - spin till TCPActiveOpen completes */
- #if SOCK_TCP_DEBUG >= 5
- dprintf("spinning in connect\n");
- #endif
- while(sp->sstate == SOCK_STATE_CONNECTING)
- {
- #if SOCK_TCP_DEBUG >= 5
- tcpCheckNotify();
- #endif
- if (spinroutine != NULL)
- (*spinroutine)();
- }
- #if SOCK_TCP_DEBUG >= 5
- dprintf("done spinning\n");
- #endif
-
- if (sp->asyncerr != 0)
- {
- (void) sock_err(sp->asyncerr);
- sp->asyncerr = 0;
- return(-1);
- }
- return(0);
- }
-
- static void
- sock_tcp_connect_done(apb)
- async_pb *apb;
- {
- SocketPtr sp = apb->sp;
-
- switch(apb->pb.tcp.ioResult)
- {
- case noErr:
- sp->asyncerr = 0;
- break;
- case invalidStreamPtr:
- sp->asyncerr = EBADF;
- break;
- case connectionExists:
- case duplicateSocket:
- sp->asyncerr = EISCONN;
- break;
- case openFailed:
- case ipDestDeadErr:
- case ipRouteErr:
- sp->asyncerr = EHOSTUNREACH;
- break;
- case ipNoFragMemErr:
- case ipDontFragErr:
- default:
- sp->asyncerr = apb->pb.tcp.ioResult;
- break;
- }
- if (sp->asyncerr != 0)
- {
- sp->sstate = SOCK_STATE_UNCONNECTED;
- return;
- }
- sp->sa.sin_addr.s_addr = apb->pb.tcp.csParam.open.localHost;
- sp->sa.sin_port = apb->pb.tcp.csParam.open.localPort;
- sp->peer.sin_addr.s_addr = apb->pb.tcp.csParam.open.remoteHost;
- sp->peer.sin_port = apb->pb.tcp.csParam.open.remotePort;
- sp->sstate = SOCK_STATE_CONNECTED;
- }
-
- /*
- * sock_tcp_listen() - put s into the listen state.
- */
- sock_tcp_listen(sp)
- SocketPtr sp;
- {
- OSErr io;
- void sock_tcp_listen_done(TCPiopb *pb);
-
- #if SOCK_TCP_DEBUG >= 2
- sock_print("sock_tcp_listen",sp);
- #endif
-
- if (sp->sstate != SOCK_STATE_UNCONNECTED)
- return(sock_err(EISCONN));
-
- sp->sstate = SOCK_STATE_LISTENING;
- io = xTCPPassiveOpen(&sp->apb.pb.tcp, sp->sa.sin_port, sock_tcp_listen_done);
- if (io != noErr)
- {
- sp->sstate = SOCK_STATE_UNCONNECTED;
- return(sock_err(io));
- }
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_listen: about to spin for port number - ticks %d\n",
- TickCount());
- #endif
- while (sp->apb.pb.tcp.csParam.open.localPort == 0)
- {
- #if SOCK_TCP_DEBUG >= 5
- tcpCheckNotify();
- #endif
- if (spinroutine != NULL)
- (*spinroutine)();
- }
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_listen: port number is %d ticks %d\n",
- sp->apb.pb.tcp.csParam.open.localPort,TickCount());
- #endif
- sp->sa.sin_addr.s_addr = sp->apb.pb.tcp.csParam.open.localHost;
- sp->sa.sin_port = sp->apb.pb.tcp.csParam.open.localPort;
- return(0);
- }
-
- static void
- sock_tcp_listen_done(TCPiopb *pb)
- {
- OSErr io;
- async_pb *apb = (async_pb *)pb;
- SocketPtr sp = apb->sp;
-
- switch(apb->pb.tcp.ioResult)
- {
- case noErr:
- #if 0
- sp->sa.sin_addr.s_addr = apb->pb.tcp.csParam.open.localHost;
- sp->sa.sin_port = apb->pb.tcp.csParam.open.localPort;
- #endif
- sp->peer.sin_addr.s_addr = apb->pb.tcp.csParam.open.remoteHost;
- sp->peer.sin_port = apb->pb.tcp.csParam.open.remotePort;
- sp->sstate = SOCK_STATE_LIS_CON;
- sp->asyncerr = 0;
- break;
- case openFailed:
- /* restart listen mode - don't know why we get this anyway */
- io = xTCPPassiveOpen(&apb->pb.tcp, sp->sa.sin_port, sock_tcp_listen_done);
- if (io != noErr)
- {
- sp->sstate = SOCK_STATE_UNCONNECTED;
- sp->asyncerr = io;
- }
- break;
- case invalidStreamPtr:
- case connectionExists:
- case duplicateSocket:
- case commandTimeout:
- default:
- sp->sstate = SOCK_STATE_UNCONNECTED;
- sp->asyncerr = apb->pb.tcp.ioResult;
- break;
- }
- }
-
- /*
- * sock_tcp_accept()
- */
- sock_tcp_accept(sp, from, fromlen)
- SocketPtr sp;
- struct sockaddr_in *from;
- int *fromlen;
- {
- int s1;
-
- #if SOCK_TCP_DEBUG >= 2
- sock_print("sock_tcp_accept",sp);
- #endif
-
- if (sp->sstate == SOCK_STATE_UNCONNECTED)
- {
- if (sp->asyncerr != 0)
- {
- (void) sock_err(sp->asyncerr);
- sp->asyncerr = 0;
- return(-1);
- }
- else
- return(sock_err(ENOTCONN));
- }
- if (sp->sstate != SOCK_STATE_LISTENING && sp->sstate != SOCK_STATE_LIS_CON)
- return(sock_err(ENOTCONN));
-
- if (sp->sstate == SOCK_STATE_LISTENING)
- {
- if (sp->nonblocking)
- return(sock_err(EWOULDBLOCK));
-
- /* Spin till sock_tcp_listen_done runs. */
- #if SOCK_TCP_DEBUG >= 5
- dprintf("--- blocking...\n");
- #endif
- while(sp->sstate == SOCK_STATE_LISTENING)
- {
- #if SOCK_TCP_DEBUG >= 5
- tcpCheckNotify();
- #endif
- if (spinroutine != NULL)
- (*spinroutine)();
- }
- #if SOCK_TCP_DEBUG >= 5
- dprintf("--- done blocking...\n");
- #endif
-
- /* got notification - was it success? */
- if (sp->sstate != SOCK_STATE_LIS_CON)
- {
- #if SOCK_TCP_DEBUG >=3
- dprintf("--- failed state %04x code %d\n",sp->sstate,sp->asyncerr);
- #endif
- (void) sock_err(sp->asyncerr);
- sp->asyncerr = 0;
- return(-1);
- }
- }
- #if SOCK_TCP_DEBUG >= 3
- dprintf("sock_tcp_accept: Have connection, peer is %08x/%d, duplicating socket.\n",
- sp->peer.sin_addr,sp->peer.sin_port);
- #endif
- /*
- * Have connection. Duplicate this socket. The client gets the connection
- * on the new socket and I create a new stream on the old socket and put it
- * in listen state.
- */
- sp->sstate = SOCK_STATE_CONNECTED;
-
- s1 = sock_free_fd(0);
- if (s1 < 0)
- {
- /* No descriptors left. Abort the incoming connection. */
- #if SOCK_TCP_DEBUG >= 2
- dprintf("sock_tcp_accept: No descriptors left.\n");
- #endif
- (void) xTCPAbort(&sp->pb.tcp);
- sp->sstate = SOCK_STATE_UNCONNECTED;
-
- /* try and put the socket back in listen mode */
- if (sock_tcp_listen(sp) < 0)
- {
- #if SOCK_TCP_DEBUG >= 1
- dprintf("sock_tcp_accept: sock_tcp_listen fails\n");
- #endif
- sp->sstate = SOCK_STATE_UNCONNECTED;
- return(-1); /* errno already set */
- }
- return(sock_err(EMFILE));
- }
-
- /* copy the incoming connection to the new socket */
- sock_dup_fd(sp->fd,s1);
- #if SOCK_TCP_DEBUG >= 3
- dprintf("sock_tcp_accept: new socket is %d\n",s1);
- sock_dump();
- #endif
-
- /* Create a new MacTCP stream on the old socket and put it into */
- /* listen state to accept more connections. */
- if (sock_tcp_new_stream(sp) < 0 || sock_tcp_listen(sp) < 0)
- {
- #if SOCK_TCP_DEBUG >= 2
- dprintf("accept: failed to restart old socket\n");
- #endif
- /* nothing to listen on */
- sp->sstate = SOCK_STATE_UNCONNECTED;
-
- /* kill the incoming connection */
- xTCPRelease(&sockets[s1].pb.tcp);
- sock_clear_fd(s1);
-
- return(-1); /* errno set */
- }
- #if SOCK_TCP_DEBUG >= 3
- dprintf("sock_tcp_accept: got new stream\n");
- sock_dump();
- #endif
-
- /* return address of partner */
- sock_copy_addr(&sockets[s1].peer, from, *fromlen);
-
- return(s1);
- }
-
- /*
- * sock_tcp_recv()
- *
- * returns bytes received or -1 and errno
- */
- sock_tcp_recv(sp, buffer, buflen, flags)
- SocketPtr sp;
- char *buffer;
- int buflen;
- int flags;
- {
- #pragma unused(flags)
- OSErr io;
-
- #if SOCK_TCP_DEBUG >= 2
- sock_print("sock_tcp_recv",sp);
- #endif
-
- /* socket hasn't finished connecting yet */
- if (sp->sstate == SOCK_STATE_CONNECTING)
- {
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_recv: connection still in progress\n");
- #endif
- if (sp->nonblocking)
- return(sock_err(EWOULDBLOCK));
-
- /* async connect and sync recv? */
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_recv: spinning on connect\n");
- #endif
- while(sp->sstate == SOCK_STATE_CONNECTING)
- {
- #if SOCK_TCP_DEBUG >= 5
- tcpCheckNotify();
- #endif
- if (spinroutine != NULL)
- (*spinroutine)();
- }
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_recv: done spinning\n");
- #endif
- }
-
- /* socket is not connected */
- if (! (sp->sstate == SOCK_STATE_CONNECTED))
- {
- /* see if the connect died (pretty poor test) */
- if (sp->sstate == SOCK_STATE_UNCONNECTED && sp->asyncerr != 0)
- {
- (void) sock_err(sp->asyncerr);
- sp->asyncerr = 0;
- return(-1);
- }
-
- /* I guess he just forgot */
- return(sock_err(ENOTCONN));
- }
-
- if (sp->dataavail == 0)
- sp->dataavail = xTCPBytesUnread(&sp->apb.pb.tcp);
- #if SOCK_TCP_DEBUG >= 3
- dprintf("sock_tcp_recv: %d bytes available\n", sp->dataavail);
- #endif
- if (sp->nonblocking && sp->dataavail == 0)
- return(sock_err(EWOULDBLOCK));
-
- io = xTCPRcv(&sp->apb.pb.tcp, buffer, buflen, (TCPIOCompletionProc)-1);
- if (io != noErr)
- return(sock_err(io));
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_recv: about to spin on xTCPRcv\n");
- #endif
- while(sp->apb.pb.tcp.ioResult == inProgress)
- {
- #if SOCK_TCP_DEBUG >= 5
- tcpCheckNotify();
- #endif
- if (spinroutine != NULL)
- (*spinroutine)();
- }
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_recv: spin done\n");
- #endif
-
- switch(sp->apb.pb.tcp.ioResult)
- {
- case noErr:
- {
- int bytesRead = sp->apb.pb.tcp.csParam.receive.rcvBuffLen;
- #if SOCK_TCP_DEBUG >= 3
- dprintf("sock_tcp_recv: got %d bytes\n", bytesRead);
- #endif
- #if (SOCK_TCP_DEBUG >= 7) || defined(TCP_PACKET_TRACE)
-
- #ifdef 0
- hex_dump(buffer, bytesRead,
- "tcp from %08x/%d\n",
- sp->peer.sin_addr.s_addr,
- sp->peer.sin_port);
- #endif
-
- #endif
- if (sp->dataavail > bytesRead)
- sp->dataavail -= bytesRead;
- else
- sp->dataavail = 0;
- return(bytesRead);
- }
- case connectionClosing:
- /* The connection is closed with all data delivered */
- #if SOCK_TCP_DEBUG >= 2
- dprintf("sock_tcp_recv: connection closed\n");
- #endif
- return(0);
-
- case connectionTerminated:
- /* The connection is aborted. */
- sp->sstate = SOCK_STATE_UNCONNECTED;
- #if SOCK_TCP_DEBUG >= 1
- dprintf("sock_tcp_recv: connection gone!\n");
- #endif
- return(sock_err(ENOTCONN));
-
- case commandTimeout:
- case connectionDoesntExist:
- case invalidStreamPtr:
- case invalidLength:
- case invalidBufPtr:
- default:
- return(sock_err(sp->apb.pb.tcp.ioResult));
- }
- }
-
-
- /*
- * sock_tcp_can_read() - returns non-zero if data or a connection is available
- */
- sock_tcp_can_read(sp)
- SocketPtr sp;
- {
- if (sp->sstate == SOCK_STATE_LIS_CON)
- return(1);
-
- if (sp->sstate == SOCK_STATE_CONNECTED)
- {
- sp->dataavail = xTCPBytesUnread(&sp->apb.pb.tcp);
- if (sp->dataavail > 0)
- return(1);
- }
-
- return(0);
- }
-
-
- /*
- * sock_tcp_send() - send the data in the (already prepared) wds
- *
- * returns bytes sent or -1 and errno
- */
- sock_tcp_send(sp, buffer, count, vector, flags/*ignored*/)
- SocketPtr sp;
- char *buffer;
- int count;
- Boolean vector;
- int flags;
- {
- #pragma unused(flags)
- OSErr io;
- void sock_tcp_send_done();
- int bytes;
-
- #if SOCK_TCP_DEBUG >= 2
- sock_print("sock_tcp_send",sp);
- #endif
-
- /* socket hasn't finished connecting yet */
- if (sp->sstate == SOCK_STATE_CONNECTING)
- {
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_send: connection still in progress\n");
- #endif
- if (sp->nonblocking)
- return(sock_err(EALREADY));
-
- /* async connect and sync send? */
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_send: spinning on connect\n");
- #endif
- while(sp->sstate == SOCK_STATE_CONNECTING)
- {
- #if SOCK_TCP_DEBUG >= 5
- tcpCheckNotify();
- #endif
- if (spinroutine != NULL)
- (*spinroutine)();
- }
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_send: done spinning\n");
- #endif
- }
-
- /* socket is not connected */
- if (! (sp->sstate == SOCK_STATE_CONNECTED))
- {
- /* see if a previous operation failed */
- if (sp->sstate == SOCK_STATE_UNCONNECTED && sp->asyncerr != 0)
- {
- (void) sock_err(sp->asyncerr);
- sp->asyncerr = 0;
- return(-1);
- }
-
- /* I guess he just forgot */
- return(sock_err(ENOTCONN));
- }
-
- /* is there a free write pb */
- if (sp->wpb[sp->nextwpb].pb.tcp.ioResult == inProgress)
- {
- /* no there isn't */
- if (sp->nonblocking)
- return(sock_err(EWOULDBLOCK));
-
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_send: spinning for free wpb\n");
- #endif
- while(sp->wpb[sp->nextwpb].pb.tcp.ioResult == inProgress)
- {
- #if SOCK_TCP_DEBUG >= 5
- tcpCheckNotify();
- #endif
- if (spinroutine != NULL)
- (*spinroutine)();
- }
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_send: done spinning\n");
- #endif
-
- /* make sure the thing that just finished worked ok */
- if (sp->asyncerr != 0)
- {
- (void) sock_err(sp->asyncerr);
- sp->asyncerr = 0;
- return(-1);
- }
- }
-
- /* copy the caller's data into the wds in the write pb */
- if (! vector)
- bytes = sock_buf_to_wds(sp, buffer, count);
- else
- bytes = sock_iov_to_wds(sp, (struct iovec *)buffer, count);
- if (bytes < 0)
- return(-1); /* errno set */
-
- #if (SOCK_TCP_DEBUG >= 7) || defined(TCP_PACKET_TRACE)
-
- #ifdef 0
- hex_dump(sp->wpb[sp->nextwpb].wds[0].ptr, sp->wpb[sp->nextwpb].wds[0].length,
- "tcp to %08x/%d\n",
- sp->peer.sin_addr.s_addr,
- sp->peer.sin_port);
- #endif
-
- #endif
-
- /* and finally .... */
- io = xTCPSend(&sp->wpb[sp->nextwpb].pb.tcp,
- &sp->wpb[sp->nextwpb].wds[0],
- true/*push*/,
- false/*urgent*/,
- sock_tcp_send_done);
- if (io != noErr)
- return(sock_err(io));
-
- sp->nextwpb = (sp->nextwpb+1) % TCP_MAX_WRITES;
-
- return(bytes);
- }
-
- static void
- sock_tcp_send_done(wpb)
- write_pb *wpb;
- {
- SocketPtr sp = wpb->sp;
-
- switch(wpb->pb.tcp.ioResult)
- {
- case noErr:
- break;
-
- case ipNoFragMemErr:
- case connectionClosing:
- case connectionTerminated:
- case connectionDoesntExist:
- sp->sstate = SOCK_STATE_UNCONNECTED;
- sp->asyncerr = ENOTCONN;
- break;
-
- case ipDontFragErr:
- case invalidStreamPtr:
- case invalidLength:
- case invalidWDS:
- default:
- sp->sstate = SOCK_STATE_UNCONNECTED;
- sp->asyncerr = wpb->pb.tcp.ioResult;
- break;
- }
- }
-
-
- /*
- * sock_tcp_can_write() - returns non-zero if a write will not block
- */
- sock_tcp_can_write(sp)
- SocketPtr sp;
- {
- if (sp->sstate == SOCK_STATE_CONNECTED)
- if (sp->wpb[sp->nextwpb].pb.tcp.ioResult != inProgress)
- return(1);
- return(0);
- }
-
- /*
- * sock_tcp_close() - close down a socket being careful about i/o in progress
- */
- sock_tcp_close(sp)
- SocketPtr sp;
- {
- OSErr io;
-
- #if SOCK_TCP_DEBUG >= 2
- sock_print("sock_tcp_close %08x",sp);
- #endif
-
- /* close the stream */
- io = xTCPClose(&sp->pb.tcp,-1);
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_close: xTCPClose returns %d\n",io);
- #endif
- switch (io)
- {
- case noErr:
- break;
- case connectionClosing:
- io = noErr;
- break;
- case connectionDoesntExist:
- case connectionTerminated:
- break;
- case invalidStreamPtr:
- default:
- return(sock_err(io));
- }
-
- /* wait for any writes in progress to finish if necessary */
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_close: spinning\n");
- #endif
- if (io == noErr)
- {
- while (sp->pb.tcp.ioResult == inProgress)
- {
- /* can we wait? */
- if (sp->nonblocking)
- return(sock_err(EWOULDBLOCK));
-
- #if SOCK_TCP_DEBUG >= 5
- tcpCheckNotify();
- #endif
- if (spinroutine != NULL)
- (*spinroutine)();
- }
- }
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_close: done spinning\n");
- #endif
-
- /* destroy the stream */
- if ((io = xTCPRelease(&sp->pb.tcp)) != noErr)
- {
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_close: xTCPRelease error %d\n",io);
- #endif
- return(sock_err(io));
- }
- /* check for errors from async writes etc */
- if (sp->asyncerr != 0)
- {
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_close: asyncerr %d\n",sp->asyncerr);
- #endif
- return(sock_err(sp->asyncerr));
- }
- return(0);
- }
-
-